package com.wdzl;


import com.wdzl.util.VerticalFlowLayout;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.*;

/**
 * 1. 目标 界面设计
 *   a.窗体创建
 *   b.
 */
public class MainFrame extends JFrame implements ActionListener {

    private DatagramSocket socket;
    private String hostIp;
    private int hostPort;
    private JTextField ipTfd;
    private JTextField sendTfd;
    private JTextField portTfd;
    private JPanel msgPanel;

    private String name;

    private DefaultListModel<String> onlineUserModel; // 存储在线用户信息的模型
    private JList<String> onlineUserList;            // 显示在线用户的组件


    /**
     * 主界面类，实现简易聊天窗口功能。
     * 包括：
     * - 窗体初始化
     * - 头像显示
     * - IP/端口输入框
     * - 消息发送与接收
     * - 在线用户列表展示
     */

    public MainFrame(String  name){
        this.name = name;
        initSocket();
        initFrame();  //初始化窗体 显示
        initHead();
        initIpPort();
        initSendMsg();
        initMsgPanel();
    }

    /**
     * 加载图像资源
     */

    /**
     * 初始化主窗口的基本属性
     *
     * 设置大小、位置、标题、图标、背景色等，并调用其他组件初始化方法
     *//**
     * 初始化主窗口的基本属性
     *
     * 设置大小、位置、标题、图标、背景色等，并调用其他组件初始化方法
     */
    private void initFrame(){
        //设置窗体大小
        setSize(550,430);
        // 显示位置
//        setLocation(200,100);
        //默认居中显示
        setLocationRelativeTo(null);

        //设置绝对布局
        setLayout(null);

        //设置标题
        setTitle("用户名: "+name+ " " +hostIp+":"+hostPort+" BiliChat v1.0");

        //设置关闭窗体时，退出程序
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        //设置禁止改变窗体大小
        setResizable(false);

        ImageIcon  qqIcon = new ImageIcon("img\\qq.jpg");

        //设置窗体图标
        setIconImage(qqIcon.getImage());

        //设置背景 #f2f7f5
        getContentPane().setBackground(Color.decode("#f2f7f5"));
        //显示窗体
//        setVisible(true);
        initOnlineUserPanel();

    }


    /**
     * 初始化UDP Socket
     *
     * 创建一个UDP数据报套接字，并获取本机IP和端口信息
     */
    private void initSocket(){
        //udp协议数据报套接字
        try {
            socket = new DatagramSocket();
            hostPort = socket.getLocalPort();
            hostIp = InetAddress.getLocalHost().getHostAddress();
        } catch (Exception e) {
            e.printStackTrace();
        }

        //启动线程 后台等待接收消息
        new RecevierThread().start();
    }

    /**
     * 初始化头像
     */
    private void initHead(){
        ImageIcon headIcon = new ImageIcon("img\\head.png");
        // 创建文本标签
        JLabel headLbl = new JLabel(headIcon);
        //设置大小
        headLbl.setSize(headIcon.getIconWidth(),headIcon.getIconHeight());
        //设置位置
        headLbl.setLocation(450,170);
        //添加到窗体中
        this.getContentPane().add(headLbl);
    }
    /**
     * 初始化IP和端口输入区域
     *
     * 包含两个标签和两个文本框，分别用于输入目标IP和端口号
     */
    private void initIpPort(){
        //创建文本标签
        JLabel ipLbl = new JLabel("IP:");
        ipLbl.setBounds(380,200,140,25);
        add(ipLbl);

        //创建输入框
        ipTfd = new JTextField("请输入对方的ip");
        ipTfd.setBounds(380,225,150,25);
        add(ipTfd);

        //创建文本标签
        JLabel portLbl = new JLabel("PORT:");
        portLbl.setBounds(380,260,140,25);
        add(portLbl);

        //创建输入框
        portTfd = new JTextField("请输入对方的端口");
        portTfd.setBounds(380,286,150,25);
        add(portTfd);
    }
    /**portTfd
     * 发送消息框
     */
    private void initSendMsg(){
        // 发送消息输入框
        sendTfd = new JTextField();

        sendTfd.setBounds(5,350,370,30);

        add(sendTfd);

        //发送消息按钮
        JButton sendBtn = new JButton("发送消息");

        sendBtn.setBounds(385,350,140,30);

        add(sendBtn);

        //给按钮绑定监听
        sendBtn.addActionListener(this);

    }
    /**
     * 初始化消息面板
     */
    private void initMsgPanel(){

        msgPanel = new JPanel();

        msgPanel.setBounds(5,5,370,330);

        msgPanel.setBackground(Color.WHITE);

        msgPanel.setLayout(new VerticalFlowLayout()); // 设置自定义的垂直布局

        JScrollPane jScrollPane = new JScrollPane(msgPanel);

        jScrollPane.setBounds(5,5,350,330);

        jScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

        jScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        add(jScrollPane);
    }

    /**
     * 按钮点击事件处理
     *
     * 当用户点击“发送消息”按钮时，启动子线程执行发送操作，避免阻塞主线程
     *
     * 并且检查消息发送是否为空，以及端口号是不是5位数
     *
     * @param e ActionEvent对象
     */
    @Override
    public void actionPerformed(ActionEvent e) {
        new Thread(() -> {
            try {
                String message = sendTfd.getText().trim(); // 获取并去除前后空格
                if (message.isEmpty()) {
                    JOptionPane.showMessageDialog(
                            MainFrame.this,
                            "消息内容不能为空，请输入要发送的内容。",
                            "提示",
                            JOptionPane.WARNING_MESSAGE
                    );
                    return;
                }

                String portStr = portTfd.getText().trim();
                if (portStr.length() != 5 || !portStr.matches("\\d{5}")) {
                    JOptionPane.showMessageDialog(
                            MainFrame.this,
                            "端口号必须是5位数字，请重新输入。",
                            "错误",
                            JOptionPane.ERROR_MESSAGE
                    );
                    return;
                }

                sendMsg(); // 执行发送逻辑
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            }
        }).start();
    }



    /**
     * 发送消息的方法
     *
     * 获取目标IP、端口和消息内容，构建DatagramPacket并通过socket发送
     *
     * @throws IOException 如果发送失败
     */
    private void sendMsg() throws IOException {
        // 获取ip
        String ip = ipTfd.getText();
        String portStr = portTfd.getText();
        int port = Integer.parseInt(portStr);
        // 获取要发送的内容
        String msg = sendTfd.getText();


        byte[] data = msg.getBytes();
        try {
            //地址
            InetAddress addr = InetAddress.getByName(ip);
            //包裹对象
            DatagramPacket packet = new DatagramPacket(data,data.length,addr,port);
            // 把包裹发出去
            socket.send(packet);
            System.out.println(">>>>>====发出消息"+ip+"==="+port);

            //发送的消息添加到消息面板
            msgAddToMsgPanel(msg,FlowLayout.RIGHT);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 将消息添加到消息面板
     *
     * 每条消息封装成一个带背景色的JLabel，并放在JPanel中进行对齐展示
     *
     * @param msg 消息内容
     * @param align 对齐方式（LEFT/RIGHT）
     */
    private void msgAddToMsgPanel(String msg,int align){
        System.out.println("========msgAddToMsgPanel========"+msg);

        JLabel msgLbl = new JLabel(msg,SwingConstants.CENTER);
        msgLbl.setForeground(Color.WHITE);

        // 调整消息背景的颜色
        Color whiteblue = new Color(0,200,255);
        msgLbl.setBackground(whiteblue);
        msgLbl.setSize(50,40);
        msgLbl.setOpaque(true);

        JPanel itemPanel = new JPanel();
        itemPanel.setBackground(Color.WHITE);

        //设置每一条消息所在面板的宽度 ，和消息面板宽度一致
        itemPanel.setPreferredSize(new Dimension(msgPanel.getWidth()-10,25));
        itemPanel.add(msgLbl);

        //设置左右对齐
        FlowLayout layout = (FlowLayout) itemPanel.getLayout();
        layout.setAlignment(align);

        msgPanel.add(itemPanel);

        //更新界面
        msgPanel.updateUI();
    }

    /**
     * 初始化在线用户面板
     *
     * 使用JList配合DefaultListModel实现动态在线用户展示
     */
    private void initOnlineUserPanel() {
        // 创建在线用户模型和列表
        onlineUserModel = new DefaultListModel<>();

        onlineUserList = new JList<>(onlineUserModel);

        onlineUserList.setBackground(Color.WHITE);

        onlineUserList.setBorder(BorderFactory.createLineBorder(Color.GRAY));

        // 添加滚动条
        JScrollPane scrollPane = new JScrollPane(onlineUserList);

        // 设置位置和大小
        scrollPane.setBounds(380, 5, 160, 170);
        add(scrollPane);
    }

    /**
     * 更新在线用户列表
     * @param ip 用户IP
     * @param port 用户端口
     */
    private void updateOnlineUsers(String ip, int port) {
        String user = "IP: " + ip + ", Port: " + port;
        boolean exists = false;

        // 检查是否已存在该用户
        for (int i = 0; i < onlineUserModel.size(); i++) {
            if (onlineUserModel.getElementAt(i).equals(user)) {
                exists = true;
                break;
            }
        }

        // 如果不存在，则添加
        if (!exists) {
            onlineUserModel.addElement(user);
        }
    }

    /**
     * 创建后台接收消息的线程
     *
     */

    class RecevierThread extends Thread {
        @Override
        public void run() {
            System.out.println("======启动后台接收消息线程====");

            byte[] data = new byte[1024];
            while (true) {
                DatagramPacket packet = new DatagramPacket(data, data.length);

                try {
                    socket.receive(packet);
                    int len = packet.getLength();
                    String msg = new String(data, 0, len);

                    System.out.println("接收到消息了：" + msg);
                    msgAddToMsgPanel(msg, FlowLayout.LEFT);

                    // 获取对方的ip和端口
                    int port = packet.getPort();
                    String ip = packet.getAddress().getHostAddress();

                    // 更新在线用户列表
                    updateOnlineUsers(ip, port);

                    // 回显到界面
                    ipTfd.setText(ip);

                    portTfd.setText(port + "");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
